package com.aric.springbootmusic.service.impl;

import com.aric.springbootmusic.entity.dto.*;
import com.aric.springbootmusic.entity.pojo.Permission;
import com.aric.springbootmusic.entity.pojo.Role;
import com.aric.springbootmusic.entity.pojo.User;
import com.aric.springbootmusic.entity.vo.*;
import com.aric.springbootmusic.enums.UserStatus;
import com.aric.springbootmusic.exceptions.NameDuplicationException;
import com.aric.springbootmusic.jwt.JWTUtils;
import com.aric.springbootmusic.mapper.UserMapper;
import com.aric.springbootmusic.service.UserService;
import com.aric.springbootmusic.utils.Result;
import com.aric.springbootmusic.utils.ResultUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@Transactional(rollbackFor=Exception.class) //开启事务
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 注册用户
     */
    @Override
    public Result register(RegisterUserDTO userDTO) throws NameDuplicationException {
        //重名验证
        LambdaQueryWrapper<User> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername,userDTO.getUsername());
        Long count = userMapper.selectCount(queryWrapper);
        if(count>0){
            throw new NameDuplicationException("该用户已经存在");
        }

        User user = User.builder()
                .username(userDTO.getUsername())
                .password(passwordEncoder.encode(userDTO.getPassword()))
                .nickname(userDTO.getNickname())
                .email(userDTO.getEmail())
                .phoneNumber(userDTO.getPhoneNumber())
                .isDelete(userDTO.getIsDelete())
                .status(userDTO.getStatus())
                .roleId(userDTO.getRoleId())
                .build();
        int i = userMapper.insert(user);
        if(i>0){
            User queryUser = userMapper.selectUserById(user.getId());
            RegisterUserVO userVO = RegisterUserVO.builder()
                    .id(queryUser.getId())
                    .username(queryUser.getUsername())
                    .nickname(queryUser.getNickname())
                    .email(queryUser.getEmail())
                    .phoneNumber(queryUser.getPhoneNumber())
                    .status(queryUser.getStatus())
                    .role(queryUser.getRole().getRoleName())
                    .build();
            return ResultUtil.getResponseResult(HttpStatus.OK.value(), "用户添加成功!",userVO);
        }
        return ResultUtil.getResponseResult(HttpStatus.INTERNAL_SERVER_ERROR.value(),"用户添加失败!",null);
    }
    //用户登陆
    @Override
    public Result login(LoginUserDTO userDTO) {
        UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(userDTO.getUsername(),userDTO.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        //认证成功后一定要把认证结果(保存授权信息)设置到SecurityContextHolder否则Spring Security将会设置一个默认的角色权限
        SecurityContextHolder.getContext().setAuthentication(authenticate);

        //如果认证没通过，给出对应的提示
        if(Objects.isNull(authenticate)){
            return ResultUtil.getResponseResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), "登陆失败!",null);
        }

        UserDetailsImpl userDetails = (UserDetailsImpl)authenticate.getPrincipal();
        User userInfo = userDetails.getUser();
        //更新用户状态
        User userState = User.builder().id(userInfo.getId()).status(UserStatus.USER_STATUS_ONLINE).build();
        userMapper.updateById(userState);

        String jwt = JWTUtils.generateJWT();

        //把完整的用户信息存入redis，userid作为key
        LoginUserVO loginUserVO = LoginUserVO.builder()
                .id(userInfo.getId())
                .username(userInfo.getUsername())
                .nickname(userInfo.getNickname())
                .email(userInfo.getEmail())
                .phoneNumber(userInfo.getPhoneNumber())
                .isDelete(userInfo.getIsDelete())
                .status(userInfo.getStatus())
                .registerTime(userInfo.getCreateTime())
                .token(jwt)
                .build();
        return ResultUtil.getResponseResult(HttpStatus.OK.value(), "登陆成功!",loginUserVO);
    }

    /**
     * 用户退出
     * @param id
     * @return
     */
    @Override
    public Result logout(String id) {
        User user = User.builder().id(id).status(UserStatus.USER_STATUS_OFFLINE).build();
        return userMapper.updateById(user) >0
                ? ResultUtil.getResponseResult(HttpStatus.OK.value(), "退出成功！",null)
                : ResultUtil.getResponseResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), "退出失败！",null);
    }

    /**
     * 左边菜单栏按钮数据
     * @param id 用户信息
     * @return 返回一个包含用户的基本信息和权限(二级)数据
     */
    @Override
    public Result getMenus(String id) {
        User user=userMapper.selectMenuByUserId(id);
        if (Objects.isNull(user)){
            return ResultUtil.getResponseResult(HttpStatus.INTERNAL_SERVER_ERROR.value(),"未知错误!",null);
        }

        List<Permission> list = user.getRole().getPermissionList();
        ArrayList<AuthorVO> authorVOS =new ArrayList<>();
        list.forEach(permission -> {
             //二级
            List<Permission> childrens = permission.getChildren();
            ArrayList<AuthorVO> authorVOChildren =new ArrayList<>();
            childrens.forEach(children->{
                AuthorVO authorVO = AuthorVO.builder()
                                      .psId(children.getPsId())
                                      .psName(children.getPsName())
                                      .psCname(children.getPsCname())
                                      .psPath(children.getPsPath())
                                      .build();
                authorVOChildren.add(authorVO);
            });

            //一级
            AuthorVO authorVO = AuthorVO.builder()
                                        .psId(permission.getPsId())
                                        .psName(permission.getPsName())
                                        .psCname(permission.getPsCname())
                                        .children(authorVOChildren)
                                        .build();
            authorVOS.add(authorVO);
        });

        MenusVO vo = MenusVO.builder()
                          .id(user.getId())
                          .username(user.getUsername())
                          .nickname(user.getNickname())
                          .authorVOS(authorVOS)
                          .build();
        return ResultUtil.getResponseResult(HttpStatus.OK.value(), "查询成功!",vo);
    }

    @Override
    public Result updateUserPassword(UpdateUserPassWordParamDTO updateUserPassWordParamDTO) {
        LambdaQueryWrapper<User> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getId, updateUserPassWordParamDTO.getId());
        User user = userMapper.selectOne(queryWrapper);
        String password = user.getPassword();//数据库中的密码
        boolean matches = passwordEncoder.matches(updateUserPassWordParamDTO.getOldPassword(), password);

        if(!matches){
            return ResultUtil.getResponseResult(HttpStatus.NOT_FOUND.value(), "旧密码输入错误!",null);
        }
        LambdaUpdateWrapper<User> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId, updateUserPassWordParamDTO.getId()).set(User::getPassword,passwordEncoder.encode(updateUserPassWordParamDTO.getNewPassword()));
        return userMapper.update(updateWrapper) > 0 ? ResultUtil.getResponseResult(HttpStatus.OK.value(), "密码修改成功!",null) :
                ResultUtil.getResponseResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), "未知错误!",null);
    }

    /**
     * 查询所有的用户数据
     * @return 返回一个分页的用户信息
     */
    @Override
    public Result findAllUser(QueryAllUserDTO allUserDTO) {
        Page<User> page=new Page<>(allUserDTO.getCurrentPage(),allUserDTO.getPageSize());

        Page<User> userPage = Objects.nonNull(allUserDTO.getKeyword()) ? userMapper.selectPageVo(page,allUserDTO.getKeyword())
                : userMapper.selectPageVo(page, null);

        if(Objects.nonNull(userPage)){
            long total = userPage.getTotal();
            List<User> users = userPage.getRecords();
            ArrayList<AllUserVO> userVOS = new ArrayList<>();
            users.forEach(user -> {
                AllUserVO userVO = AllUserVO.builder()
                        .id(user.getId())
                        .username(user.getUsername())
                        .nickname(user.getNickname())
                        .email(user.getEmail())
                        .phoneNumber(user.getPhoneNumber())
                        .status(user.getStatus())
                        .role(user.getRole().getRoleName())
                        .build();
                userVOS.add(userVO);
            });

            FindAllUserVO userVO = FindAllUserVO.builder().users(userVOS).total(total).build();
            return ResultUtil.getResponseResult(HttpStatus.OK.value(), "查询成功!",userVO);
        }
        return ResultUtil.getResponseResult(HttpStatus.OK.value(), "查询成功!",null);
    }

    /**
     * 获取该用户所具有的三级权限信息
     * @param id 用户id
     * @return
     */
    @Override
    public Result getAuthoritys(String id) {
        List<String> authority=userMapper.findAllUserAuthority(id);
        if(Objects.nonNull(authority)){
            return ResultUtil.getResponseResult(HttpStatus.OK.value(),"查询权限成功!" ,authority);
        }
        return ResultUtil.getResponseResult(HttpStatus.OK.value(),"该用户没有任何权限" ,null);
    }

    /**
     * 更新用户状态
     * @param statusDTO
     * @return
     */
    @Override
    public Result updateUserStatus(UserStatusDTO statusDTO) {
        User user = User.builder()
                .id(statusDTO.getId())
                .status(statusDTO.getStatus())
                .build();
        int i = userMapper.updateById(user);
        //返回错误，未修改
        return i>0 ? ResultUtil.getResponseResult(HttpStatus.OK.value(), "状态更改成功!",null) : ResultUtil.getResponseResult(HttpStatus.NOT_MODIFIED.value(), "状态修改失败!",null);
    }

    /**
     * 删除用户
     * @param id 用户id
     * @return
     */
    @Override
    public Result deleteUser(String id) {
        return userMapper.deleteById(id) > 0 ? ResultUtil.getResponseResult(HttpStatus.OK.value(), "删除成功!",null) : ResultUtil.getResponseResult(HttpStatus.NOT_MODIFIED.value(), "删除失败!",null);
    }

    @Override
    public Result findUserById(String id) {
        User user = userMapper.selectById(id);
        if(Objects.nonNull(user)){
            EditUserVO userVO = EditUserVO.builder()
                    .id(user.getId())
                    .nickname(user.getNickname())
                    .phoneNumber(user.getPhoneNumber())
                    .email(user.getEmail())
                    .build();
            return ResultUtil.getResponseResult(HttpStatus.OK.value(), "查询成功！",userVO);
        }
        return ResultUtil.getResponseResult(HttpStatus.SERVICE_UNAVAILABLE.value(), "查询失败",null);
    }

    @Override
    public Result updateUser(EditUserDTO userDTO) {
        User user = User.builder()
                .id(userDTO.getId())
                .nickname(userDTO.getNickname())
                .email(userDTO.getEmail())
                .phoneNumber(userDTO.getPhoneNumber())
                .build();
        int i = userMapper.updateById(user);
        if(i>0){
            User queryUser = userMapper.selectUserById(userDTO.getId());
            RegisterUserVO userVO = RegisterUserVO.builder()
                    .id(queryUser.getId())
                    .username(queryUser.getUsername())
                    .nickname(queryUser.getNickname())
                    .email(queryUser.getEmail())
                    .phoneNumber(queryUser.getPhoneNumber())
                    .status(queryUser.getStatus())
                    .role(queryUser.getRole().getRoleName())
                    .build();
            return ResultUtil.getResponseResult(HttpStatus.OK.value(), "用户更新成功!",userVO);
        }
        return ResultUtil.getResponseResult(HttpStatus.SERVICE_UNAVAILABLE.value(),"更新失败!",null);
    }

    @Override
    public Result selectUserRoleById(String id) {
        String roleName=userMapper.findUserRoleById(id);
        if(Objects.nonNull(roleName)){
           return ResultUtil.getResponseResult(HttpStatus.OK.value(), "查询成功!",roleName);
        }
        return ResultUtil.getResponseResult(HttpStatus.SERVICE_UNAVAILABLE.value(), "查询失败!",null);
    }

    @Override
    public Result modifyUserRole(EditUserRoleDTO dto) {
        User user = User.builder()
                .id(dto.getId())
                .roleId(dto.getRoleId())
                .build();
        int i = userMapper.updateById(user);
        if(i>0){
            User queryUser =userMapper.selectUserById(dto.getId());
            RegisterUserVO userVO = RegisterUserVO.builder()
                    .id(queryUser.getId())
                    .username(queryUser.getUsername())
                    .nickname(queryUser.getNickname())
                    .email(queryUser.getEmail())
                    .phoneNumber(queryUser.getPhoneNumber())
                    .status(queryUser.getStatus())
                    .role(queryUser.getRole().getRoleName())
                    .build();
            return ResultUtil.getResponseResult(HttpStatus.OK.value(), "角色更新成功!",userVO);
        }
        return ResultUtil.getResponseResult(HttpStatus.SERVICE_UNAVAILABLE.value(),"角色更新失败!",null);
    }
}
